
package xj.graph2d.app.resources;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;

import javax.swing.Icon;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.ImageTranscoder;

public class SVGIcon implements Icon { 

  public SVGIcon(InputStream in, Dimension dim) { 
    this(in, false, dim);
  }

  public SVGIcon(InputStream in, boolean zipped, Dimension dim) { 
    this.width = dim.width;
    this.height = dim.height;

    if (in != null) { 
      try { 
	if (zipped) { 
	  in = new GZIPInputStream(in);
	}
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	byte[] b = new byte[1024];
	while (true) {
	  int count = in.read(b);
	  if (count < 0)
	    break;
	  baos.write(b, 0, count);
	}
	this.svgBytes = baos.toByteArray();
      } catch (IOException e) { 
	e.printStackTrace();
      }
    }
  }

  public SVGIcon(byte[] svgBytes, Dimension dim) { 
    this.width = dim.width;
    this.height = dim.height;
    this.svgBytes = svgBytes;    
  }

  protected int width, height; ;
  protected BufferedImage bufferedImage;
  protected byte[] svgBytes;

  public int getIconWidth() {
    return width;
  }

  public int getIconHeight() {
    return height;
  }

  public void setDimension(Dimension dim) { 
    if (this.width != dim.width ||
	this.height != dim.height) { 
      this.width = dim.width;
      this.height = dim.height;
      bufferedImage = null;
      renderSVG();
    }
  }

  public byte[] getSvgBytes() {
    return this.svgBytes;
  }

  public void paintIcon(Component c, Graphics g, int x, int y) {
    // System.out.println("Paint " + bufferedImage);
    if (bufferedImage == null) {
      renderSVG();
    }
    if (bufferedImage != null) {
      g.drawImage(bufferedImage, x, y, null);
    }
  }
  
  protected void renderSVG() { 
    if (svgBytes != null && 
	width != 0 && 
	height != 0) {
      BufferedImageTranscoder t = new BufferedImageTranscoder();
      t.setDimensions(width, height);

      try { 
	InputStream in = new ByteArrayInputStream(svgBytes);
	TranscoderInput ti = new TranscoderInput(in);    
	t.transcode(ti, null);
	bufferedImage = t.getBufferedImage();
	width = bufferedImage.getWidth();
	height = bufferedImage.getHeight();
      } catch (TranscoderException e) { 
	e.printStackTrace();
      }
    }
  }

  protected static InputStream constructFromZipStream(InputStream zippedStream)
    throws IOException {
    GZIPInputStream gis = new GZIPInputStream(zippedStream);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    
    byte[] buf = new byte[2048];
    int len;
    while ((len = gis.read(buf)) != -1) {
      baos.write(buf, 0, len);
    }
    
    return new ByteArrayInputStream(baos.toByteArray());
  }
  
  /**
   * A transcoder that generates a BufferedImage.
   */
  public static class BufferedImageTranscoder extends ImageTranscoder {
    
    /**
     * The BufferedImage generated from the SVG document.
     */
    protected BufferedImage bufferedImage;
    
    /**
     * Creates a new ARGB image with the specified dimension.
     * 
     * @param width
     *            the image width in pixels
     * @param height
     *            the image height in pixels
     */
    @Override
    public BufferedImage createImage(int width, int height) {
      return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    }
    
    /**
     * Writes the specified image to the specified output.
     * 
     * @param img
     *            the image to write
     * @param output
     *            the output where to store the image
     * @param TranscoderException
     *            if an error occured while storing the image
     */
    @Override
    public void writeImage(BufferedImage img, TranscoderOutput output)
      throws TranscoderException {
      bufferedImage = img;
    }
    
    /**
     * Returns the {@link BufferedImage} generated from the SVG document.
     * 
     * @return {@link BufferedImage} generated from the SVG document.
     */
    public BufferedImage getBufferedImage() {
      return bufferedImage;
    }
    
    /**
     * Set the dimensions to be used for the image.
     * 
     * @param w
     *            Width.
     * @param h
     *            Height.
     */
    public void setDimensions(int w, int h) {
      hints.put(KEY_WIDTH, new Float(w));
      hints.put(KEY_HEIGHT, new Float(h));
    }
  }
  
}
